<!DOCTYPE html>
<html>

<head>
    <title>Bootstrap5 实例</title>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <link href="https://cdn.staticfile.net/twitter-bootstrap/5.1.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.staticfile.net/twitter-bootstrap/5.1.1/js/bootstrap.bundle.min.js"></script>
</head>

<body>
    <div class="container border p-3">
        <div class="input-group mb-3">
            <span class="btn btn-primary input-group-text" onclick="dCanvas.clsDraw()">clsDraw</span>
            <span class="btn btn-primary input-group-text" onclick="dCanvas.reDraw()">reDraw</span>
            <input id="fillText" type="text" class="form-control" value="LWF">
        </div>
        <canvas id="titleCanvas" class="border" width="800" height="75"></canvas><br>
        <canvas id="bodyCanvas" class="border" width="800" height="600"></canvas>
        <script>
            class canvasListener {
                constructor(canvasName) {
                    this.canvas = document.getElementById(canvasName);
                    this.ctx = this.canvas.getContext('2d');
                    this.painting = false; // 标记是否正在画图
                    // 添加事件监听器
                    this.canvas.addEventListener('mousedown', this.startPosition);
                    this.canvas.addEventListener('mouseup', this.finishedPosition);
                    this.canvas.addEventListener('mousemove', this.draw);
                }
                startPosition(e) {
                    let x = e.clientX, y = e.clientY;
                    this.painting = true;
                    dCanvas.listener("mousedown", x, y);
                }
                finishedPosition(e) {
                    let x = e.clientX, y = e.clientY;
                    this.painting = false;
                    dCanvas.listener("mouseup", x, y);
                }
                draw(e) {
                    if (!this.painting) return;
                    let x = e.clientX, y = e.clientY;
                    dCanvas.listener("mousemove", x, y);
                }
            }
            const dc = new canvasListener("bodyCanvas");
            class drawCanvas {
                constructor(canvasName) {
                    this.canvas = document.getElementById(canvasName);
                    this.ctx = this.canvas.getContext('2d');
                    this.mousedownData = [];
                    this.mouseupData = [];
                    this.mousemoveData = [];
                    this.tuceng = [];
                    this.fun = "线段";
                    this.painting = false;
                    this.zoom = 3;
                    this.grid = 5;
                    this.current = [297, 210];
                    this.zhiZhang = {
                        A: [[841, 1189], [597, 840], [420, 597], [297, 420], [210, 297], [148, 210], [105, 144]],
                        B: [[787, 1092], [520, 740], [370, 520], [260, 370], [185, 260], [130, 185]]
                    }
                    this.drawGrid();
                }
                listener(action, yx, yy) {
                    let ww = this.grid * this.zoom;
                    let x = Math.floor(((yx - this.canvas.offsetLeft) - ww / 2) / ww + 1) * ww;
                    let y = Math.floor(((yy - this.canvas.offsetTop) - ww / 2) / ww + 1) * ww;
                    switch (action) {
                        case "mousedown":
                            this.painting = true;
                            this.mousedownData = [x, y];
                            this.mousemoveData = [];
                            break;
                        case "mouseup":
                            this.mouseupData = [x, y];
                            if (this.fun == "线段") {
                                this.tuceng.push({ "线段": [this.mousedownData, this.mouseupData] });
                            } else if (this.fun == "椭圆") {
                                this.tuceng.push({ "椭圆": [this.mousedownData, this.mouseupData] });
                            } else if (this.fun == "矩形") {
                                this.tuceng.push({ "矩形": [this.mousedownData, this.mouseupData] });
                            } else if (this.fun == "圆角矩形") {
                                this.tuceng.push({ "圆角矩形": [this.mousedownData, this.mouseupData] });
                            } else if (this.fun == "菱形") {
                                this.tuceng.push({ "菱形": [this.mousedownData, this.mouseupData] });
                            } else if (this.fun == "箭头") {
                                this.tuceng.push({ "箭头": [this.mousedownData, this.mouseupData] });
                            }
                            this.painting = false;
                            break;
                        case "mousemove":
                            this.mousemoveData.push([x, y]);
                            break;
                    }
                    this.reDraw();
                    switch (this.fun) {
                        case "线段":
                            this.draw_line(this.mousedownData[0], this.mousedownData[1], x, y);
                            break;
                        case "椭圆":
                            this.draw_ellipse(this.mousedownData[0], this.mousedownData[1], x, y);
                            break;
                        case "矩形":
                            this.draw_rectangle(this.mousedownData[0], this.mousedownData[1], x, y);
                            break;
                        case "圆角矩形":
                            this.draw_rounded_rectangle(this.mousedownData[0], this.mousedownData[1], x, y);
                            break;
                        case "菱形":
                            this.draw_diamond(this.mousedownData[0], this.mousedownData[1], x, y);
                            break;
                        case "箭头":
                            this.draw_jiantou(this.mousedownData[0], this.mousedownData[1], x, y);
                            break;
                    }
                }
                drawGrid() {
                    let x = 0, y = 0;
                    let width = this.grid * this.zoom * x;
                    let height = this.grid * this.zoom * y;
                    while (width <= this.canvas.width) {
                        while (height <= this.canvas.height) {
                            this.ctx.beginPath();
                            this.ctx.lineWidth = 1;
                            this.ctx.lineCap = 'round';
                            this.ctx.strokeStyle = '#000000';
                            this.ctx.lineTo(width, height);
                            this.ctx.stroke();
                            y++;
                            height = this.grid * this.zoom * y;
                        }
                        x++;
                        y = 0;
                        width = this.grid * this.zoom * x;
                        height = this.grid * this.zoom * y;
                    }
                }
                clsDraw() {
                    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                    this.drawGrid();
                }
                reDraw() {
                    this.clsDraw();
                    for (let index in this.tuceng) {
                        for (let type in this.tuceng[index]) {
                            switch (type) {
                                case "线段":
                                    this.draw_line(
                                        this.tuceng[index]["线段"][0][0],
                                        this.tuceng[index]["线段"][0][1],
                                        this.tuceng[index]["线段"][1][0],
                                        this.tuceng[index]["线段"][1][1]
                                    );
                                    break;
                                case "椭圆":
                                    this.draw_ellipse(
                                        this.tuceng[index]["椭圆"][0][0],
                                        this.tuceng[index]["椭圆"][0][1],
                                        this.tuceng[index]["椭圆"][1][0],
                                        this.tuceng[index]["椭圆"][1][1]
                                    );
                                    break;
                                case "矩形":
                                    this.draw_rectangle(
                                        this.tuceng[index]["矩形"][0][0],
                                        this.tuceng[index]["矩形"][0][1],
                                        this.tuceng[index]["矩形"][1][0],
                                        this.tuceng[index]["矩形"][1][1]
                                    );
                                    break;
                                case "圆角矩形":
                                    this.draw_rounded_rectangle(
                                        this.tuceng[index]["圆角矩形"][0][0],
                                        this.tuceng[index]["圆角矩形"][0][1],
                                        this.tuceng[index]["圆角矩形"][1][0],
                                        this.tuceng[index]["圆角矩形"][1][1]
                                    );
                                    break;
                                case "菱形":
                                    this.draw_diamond(
                                        this.tuceng[index]["菱形"][0][0],
                                        this.tuceng[index]["菱形"][0][1],
                                        this.tuceng[index]["菱形"][1][0],
                                        this.tuceng[index]["菱形"][1][1]
                                    );
                                    break;
                                case "箭头":
                                    this.draw_jiantou(
                                        this.tuceng[index]["箭头"][0][0],
                                        this.tuceng[index]["箭头"][0][1],
                                        this.tuceng[index]["箭头"][1][0],
                                        this.tuceng[index]["箭头"][1][1]
                                    );
                                    break;
                                default:
                                    console.log(this.tuceng[index]);
                                    break;
                            }
                        }
                    }
                }
                draw_line(sx, sy, ex, ey, lineWidth = 5) {
                    //this.ctx.lineWidth = lineWidth;
                    this.ctx.lineCap = 'round';
                    this.ctx.strokeStyle = 'black';
                    this.ctx.beginPath();
                    this.ctx.moveTo(sx, sy);
                    this.ctx.lineTo(ex, ey);
                    this.ctx.stroke();
                }
                draw_ellipse(sx, sy, ex, ey) {
                    let text = document.getElementById("fillText").value;
                    let cx = (sx + ex) / 2;
                    let cy = (sy + ey) / 2;
                    let rx = Math.abs(ex - sx) / 2;
                    let ry = Math.abs(ey - sy) / 2;
                    this.ctx.beginPath();
                    this.ctx.ellipse(cx, cy, rx, ry, 0, 0, 2 * Math.PI, false);
                    this.ctx.stroke();
                    this.ctx.font = "20px 宋体";
                    this.ctx.textAlign = 'center';
                    this.ctx.textBaseline = 'middle';
                    this.ctx.fillStyle = 'black';
                    this.ctx.fillText(text, cx, cy);
                }
                draw_rectangle(startX, startY, currentX, currentY) {
                    let text = document.getElementById("fillText").value;
                    const x = Math.min(startX, currentX);
                    const y = Math.min(startY, currentY);
                    var width = Math.max(startX, currentX) - Math.min(startX, currentX);
                    var height = Math.max(startY, currentY) - Math.min(startY, currentY);
                    this.ctx.beginPath();
                    this.ctx.lineTo(x, y);
                    this.ctx.lineTo(x + width, y);
                    this.ctx.lineTo(x + width, y + height);
                    this.ctx.lineTo(x, y + height);
                    this.ctx.closePath();
                    this.ctx.stroke();
                    let cx = (startX + currentX) / 2;
                    let cy = (startY + currentY) / 2;
                    this.ctx.font = "20px 宋体";
                    this.ctx.textAlign = 'center';
                    this.ctx.textBaseline = 'middle';
                    this.ctx.fillStyle = 'black';
                    this.ctx.fillText(text, cx, cy);
                }
                draw_rounded_rectangle(startX, startY, currentX, currentY) {
                    let text = document.getElementById("fillText").value;
                    const x = Math.min(startX, currentX);
                    const y = Math.min(startY, currentY);
                    var width = Math.max(startX, currentX) - Math.min(startX, currentX);
                    var height = Math.max(startY, currentY) - Math.min(startY, currentY);
                    var radius = 10;
                    this.ctx.beginPath();
                    this.ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 1.5);
                    this.ctx.lineTo(x + width - radius, y);
                    this.ctx.arc(x + width - radius, y + radius, radius, Math.PI * 1.5, Math.PI * 2);
                    this.ctx.lineTo(x + width, y + height - radius);
                    this.ctx.arc(x + width - radius, y + height - radius, radius, 0, Math.PI * 0.5);
                    this.ctx.lineTo(x + radius, y + height);
                    this.ctx.arc(x + radius, y + height - radius, radius, Math.PI * 0.5, Math.PI);
                    this.ctx.closePath();
                    this.ctx.stroke();
                    let cx = (startX + currentX) / 2;
                    let cy = (startY + currentY) / 2;
                    this.ctx.font = "20px 宋体";
                    this.ctx.textAlign = 'center';
                    this.ctx.textBaseline = 'middle';
                    this.ctx.fillStyle = 'black';
                    this.ctx.fillText(text, cx, cy);
                }
                draw_diamond(startX, startY, currentX, currentY) {
                    let text = document.getElementById("fillText").value;
                    const x = Math.min(startX, currentX);
                    const y = Math.min(startY, currentY);
                    var width = Math.max(startX, currentX) - Math.min(startX, currentX);
                    var height = Math.max(startY, currentY) - Math.min(startY, currentY);
                    this.ctx.beginPath();
                    this.ctx.lineTo(x + width / 2, y);
                    this.ctx.lineTo(x + width, y + height / 2);
                    this.ctx.lineTo(x + width / 2, y + height);
                    this.ctx.lineTo(x, y + height / 2);
                    this.ctx.closePath();
                    this.ctx.stroke();
                    let cx = (startX + currentX) / 2;
                    let cy = (startY + currentY) / 2;
                    this.ctx.font = "20px 宋体";
                    this.ctx.textAlign = 'center';
                    this.ctx.textBaseline = 'middle';
                    this.ctx.fillStyle = 'black';
                    this.ctx.fillText(text, cx, cy);
                }
                draw_jiantou(startX, startY, endX, endY) {
                    this.ctx.beginPath();
                    this.ctx.moveTo(startX, startY);
                    this.ctx.lineTo(endX, endY);
                    this.ctx.strokeStyle = 'black';
                    var dx = endX - startX;
                    var dy = endY - startY;
                    var angle = Math.atan2(dy, dx); // 弧度
                    let endX1 = endX - 20 * Math.cos(angle - 0.35)
                    let endY1 = endY - 20 * Math.sin(angle - 0.35)
                    let endX2 = endX - 20 * Math.cos(angle + 0.35)
                    let endY2 = endY - 20 * Math.sin(angle + 0.35)
                    this.ctx.moveTo(endX1, endY1); // 箭头末端的点  
                    this.ctx.lineTo(endX, endY); // 箭头左侧的点  
                    this.ctx.lineTo(endX2, endY2); // 箭头右侧的点  
                    this.ctx.stroke();
                }
            }
            const dCanvas = new drawCanvas("bodyCanvas");
        </script>
        <script>
            class titleCanvasListener {
                constructor(canvasName) {
                    this.canvas = document.getElementById(canvasName);
                    this.ctx = this.canvas.getContext('2d');
                    this.painting = false;
                    this.canvas.addEventListener('mousedown', this.startPosition);
                    this.canvas.addEventListener('mouseup', this.finishedPosition);
                    this.canvas.addEventListener('mousemove', this.draw);
                }
                startPosition(e) {
                    let x = e.clientX, y = e.clientY;
                    this.painting = true;
                    dtCanvas.listener("mousedown", x, y);
                }
                finishedPosition(e) {
                    let x = e.clientX, y = e.clientY;
                    this.painting = false;
                    dtCanvas.listener("mouseup", x, y);
                }
                draw(e) {
                    if (!this.painting) return;
                    let x = e.clientX, y = e.clientY;
                    dtCanvas.listener("mousemove", x, y);
                }
            }
            const titleCanvas = new titleCanvasListener("titleCanvas");

            class drawTitleCanvas {
                constructor(canvasName) {
                    this.canvas = document.getElementById(canvasName);
                    this.ctx = this.canvas.getContext('2d');
                    this.grid = 8;
                    this.canvas.width = 100 * this.grid;
                    this.canvas.height = 6 * this.grid;
                    this.ctx.lineWidth = 3;
                    this.ctx.lineCap = 'round';
                    this.draw_line('red');
                    this.draw_ellipse();
                    this.draw_rectangle();
                    this.draw_rounded_rectangle();
                    this.draw_diamond();
                    this.draw_jiantou();
                    this.strokeStyleList = ["red", "black", "black", "black", "black", "black"];
                }
                listener(action, x, y) {
                    let row = Math.floor((x - this.canvas.offsetLeft) / this.grid);
                    let col = Math.floor((y - this.canvas.offsetTop) / this.grid);
                    switch (action) {
                        case "mousedown":
                            let cIndex = 0;
                            if (col >= 1 && col <= 5) {
                                if (row >= 1 && row <= 7) {
                                    cIndex = 1;
                                    dCanvas.fun = '线段'
                                } else if (row >= 8 && row <= 14) {
                                    cIndex = 2;
                                    dCanvas.fun = '椭圆'
                                } else if (row >= 15 && row <= 21) {
                                    cIndex = 3;
                                    dCanvas.fun = '矩形'
                                } else if (row >= 22 && row <= 28) {
                                    cIndex = 4;
                                    dCanvas.fun = '圆角矩形'
                                } else if (row >= 29 && row <= 35) {
                                    cIndex = 5;
                                    dCanvas.fun = '菱形'
                                } else if (row >= 36 && row <= 42) {
                                    cIndex = 6;
                                    dCanvas.fun = '箭头'
                                }
                            }
                            if (cIndex > 0) {
                                for (let index in this.strokeStyleList) {
                                    if (index == cIndex - 1) {
                                        this.strokeStyleList[index] = "red";
                                    } else {
                                        this.strokeStyleList[index] = "black";
                                    }
                                }
                                this.reDraw();
                            } else {
                                dCanvas.ctx.clearRect(0, 0, dCanvas.canvas.width, dCanvas.canvas.height);
                            }
                            break;
                        case "mouseup":
                            break;
                        case "mousemove":
                            break;
                    }
                }
                reDraw() {
                    this.ctx.clearRect(0, 0, this.canvas.width, this.canvas.height);
                    this.draw_line(this.strokeStyleList[0]);
                    this.draw_ellipse(this.strokeStyleList[1]);
                    this.draw_rectangle(this.strokeStyleList[2]);
                    this.draw_rounded_rectangle(this.strokeStyleList[3]);
                    this.draw_diamond(this.strokeStyleList[4]);
                    this.draw_jiantou(this.strokeStyleList[5]);
                }
                draw_line(strokeStyle = 'black') {
                    let zGrid = this.grid * 2;
                    this.ctx.strokeStyle = strokeStyle;
                    this.ctx.beginPath();
                    this.ctx.lineTo(this.grid, this.grid);
                    this.ctx.lineTo(this.grid, this.grid * 5);
                    this.ctx.lineTo(this.grid * 7, this.grid * 5);
                    this.ctx.lineTo(this.grid * 7, this.grid);
                    this.ctx.lineTo(this.grid, this.grid);
                    this.ctx.moveTo(this.grid * 2, this.grid * 3);
                    this.ctx.lineTo(this.grid * 6, this.grid * 3);
                    this.ctx.stroke();
                }
                draw_ellipse(strokeStyle = 'black') {
                    let zGrid = this.grid * 2;
                    this.ctx.strokeStyle = strokeStyle;
                    this.ctx.beginPath();
                    this.ctx.ellipse(this.grid * 11, this.grid * 3, this.grid * 3, this.grid * 2, 0, 0, 2 * Math.PI, false);
                    this.ctx.stroke();
                }
                draw_rectangle(strokeStyle = 'black') {
                    let zGrid = this.grid * 2;
                    this.ctx.strokeStyle = strokeStyle;
                    this.ctx.beginPath();
                    this.ctx.rect(this.grid * 15, this.grid, this.grid * 6, this.grid * 4);
                    this.ctx.stroke();
                }
                draw_rounded_rectangle(strokeStyle = 'black') {
                    const x = this.grid * 22;
                    const y = this.grid;
                    var width = this.grid * 6;
                    var height = this.grid * 4;
                    var radius = this.grid;
                    this.ctx.strokeStyle = strokeStyle;
                    this.ctx.beginPath();
                    this.ctx.arc(x + radius, y + radius, radius, Math.PI, Math.PI * 1.5);
                    this.ctx.lineTo(x + width - radius, y);
                    this.ctx.arc(x + width - radius, y + radius, radius, Math.PI * 1.5, Math.PI * 2);
                    this.ctx.lineTo(x + width, y + height - radius);
                    this.ctx.arc(x + width - radius, y + height - radius, radius, 0, Math.PI * 0.5);
                    this.ctx.lineTo(x + radius, y + height);
                    this.ctx.arc(x + radius, y + height - radius, radius, Math.PI * 0.5, Math.PI);
                    this.ctx.closePath();
                    this.ctx.stroke();
                }
                draw_diamond(strokeStyle = 'black') {
                    const x = this.grid * 29;
                    const y = this.grid;
                    var width = this.grid * 6;
                    var height = this.grid * 4;
                    this.ctx.strokeStyle = strokeStyle;
                    this.ctx.beginPath();
                    this.ctx.lineTo(x + width / 2, y);
                    this.ctx.lineTo(x + width, y + height / 2);
                    this.ctx.lineTo(x + width / 2, y + height);
                    this.ctx.lineTo(x, y + height / 2);
                    this.ctx.closePath();
                    this.ctx.stroke();
                }
                draw_jiantou(strokeStyle = 'black') {
                    const x = this.grid * 35;
                    const y = this.grid;
                    this.ctx.strokeStyle = strokeStyle;
                    this.ctx.beginPath();
                    this.ctx.moveTo(x + this.grid, y);
                    this.ctx.lineTo(x + this.grid, y + this.grid * 4);
                    this.ctx.lineTo(x + this.grid * 7, y + this.grid * 4);
                    this.ctx.lineTo(x + this.grid * 7, y);
                    this.ctx.lineTo(x + this.grid, y);
                    var startX = this.grid * 37;
                    var startY = this.grid * 3;
                    var endX = this.grid * 41;
                    var endY = this.grid * 3;
                    this.ctx.moveTo(startX, startY);
                    this.ctx.lineTo(endX, endY);
                    var dx = endX - startX;
                    var dy = endY - startY;
                    var angle = Math.atan2(dy, dx); // 弧度
                    let endX1 = endX - 20 * Math.cos(angle - 0.35)
                    let endY1 = endY - 20 * Math.sin(angle - 0.35)
                    let endX2 = endX - 20 * Math.cos(angle + 0.35)
                    let endY2 = endY - 20 * Math.sin(angle + 0.35)
                    this.ctx.moveTo(endX1, endY1); // 箭头末端的点  
                    this.ctx.lineTo(endX, endY); // 箭头左侧的点  
                    this.ctx.lineTo(endX2, endY2); // 箭头右侧的点  
                    this.ctx.stroke();
                }
            }
            const dtCanvas = new drawTitleCanvas("titleCanvas");
        </script>
    </div>
</body>

</html>